//
// Created by yfux on 2022/4/19.
//

#include "Log.h"
#include "AudioPlayer.h"


AudioPlayer::AudioPlayer(int channelId, JavaCallHelper *helper, AVCodecContext *avCodecContext,
                         AVRational &timeBase) : BasePlayer(channelId, helper, avCodecContext,
                                                            timeBase) {

}

AudioPlayer::~AudioPlayer() {

}

void AudioPlayer::stop() {
    isPlaying = false;
    javaCallHelper = NULL;
    setEnable(false);
    pthread_join(decodeThread, 0);
    pthread_join(playThread, 0);
    _releaseOpenSL();
    if (swrContext) {
        swr_free(&swrContext);
        swrContext = NULL;
    }
}

void *adecode_t(void *args) {
//    LOGE("adecode_t begin...");
    AudioPlayer *audioPlayer = static_cast<AudioPlayer *>(args);
    audioPlayer->_decode();
//    LOGE("adecode_t end...");
    return 0;
}

void AudioPlayer::decode() {
    pthread_create(&decodeThread, NULL, adecode_t, this);
}


void *aplay_t(void *args) {
    AudioPlayer *audioPlayer = static_cast<AudioPlayer *>(args);
    audioPlayer->_play();
    return 0;
}

void AudioPlayer::play() {
//    LOGE("play begin...");
//    swrContext = swr_alloc();
    swrContext = swr_alloc_set_opts(
            NULL,
            AV_CH_LAYOUT_STEREO,
//            av_get_default_channel_layout(avCodecContext->channels),
            AV_SAMPLE_FMT_S16,
            avCodecContext->sample_rate,
            av_get_default_channel_layout(avCodecContext->channels),
            avCodecContext->sample_fmt,
            avCodecContext->sample_rate,
            0, NULL
    );
    swr_init(swrContext);
    LOGE("swrContext: %p", swrContext);
    buffer = static_cast<uint8_t *>(av_malloc(MAX_AUDIO_FARME_SIZE));
    LOGE("buffer : %x", buffer);
    isPlaying = true;
    setEnable(true);
    //decode
    decode();
    //play
    pthread_create(&playThread, NULL, aplay_t, this);
//    LOGE("play end...");
}

void AudioPlayer::_decode() {
//    LOGE("_decode begin...");
    AVPacket *avPacket = NULL;
    AVFrame *avFrame = NULL;
    int ret;
    while (isPlaying) {
        ret = avPacket_queue.pop(avPacket);
        if (!isPlaying) break;
        if (!ret) continue;
        ret = avcodec_send_packet(avCodecContext, avPacket);
        releaseAvPacket(avPacket);
        if (ret < 0)break;
        avFrame = av_frame_alloc();
        ret = avcodec_receive_frame(avCodecContext, avFrame);
        if (ret == AVERROR(EAGAIN)) continue;
        else if (ret < 0) break;
        while (avFrame_queue.size() > 50 && isPlaying) {
            av_usleep(1000 * 10 * avFrame_queue.size() / 100);
//            LOGE("queue.size() : %d", avFrame_queue.size());
        }
        avFrame_queue.push(avFrame);
    }
    releaseAvPacket(avPacket);
}

void bqPlayerCallback(SLAndroidSimpleBufferQueueItf queue, void *pContext) {
    AudioPlayer *audioPlayer = static_cast<AudioPlayer *>(pContext);
    int dataSize = audioPlayer->getData();
//    LOGE("dataSize = %d", dataSize);
    if (dataSize > 0) {
        (*queue)->Enqueue(queue, audioPlayer->buffer, dataSize);
    }
}

int AudioPlayer::getData() {
    int ret;
    int dataSize = 0;
    AVFrame *avFrame = NULL;
    while (isPlaying) {
        ret = avFrame_queue.pop(avFrame);
        if (!isPlaying) break;
        if (!ret) continue;
//        if (avFrame->channel_layout == 0 && avFrame->channels > 0) {
//            avFrame->channel_layout = av_get_default_channel_layout(avFrame->channels);
//        } else if (avFrame->channels == 0 && avFrame->channel_layout > 0) {
//            avFrame->channels = av_get_channel_layout_nb_channels(avFrame->channel_layout);
//        }
//        swr_alloc_set_opts(
//                swrContext,
//                AV_CH_LAYOUT_STEREO,
////            av_get_default_channel_layout(avCodecContext->channels),
//                AV_SAMPLE_FMT_S16,
//                avFrame->sample_rate,
//                avFrame->channel_layout,
//                static_cast<AVSampleFormat>(avFrame->format),
//                avFrame->sample_rate,
//                0, NULL
//        );
        int nb = swr_convert(swrContext, &buffer, MAX_AUDIO_FARME_SIZE,
                             (const uint8_t **) avFrame->data, avFrame->nb_samples);
        if (nb < 0)LOGE("swr_convert error!");
//        dataSize = av_samples_get_buffer_size(NULL,
//                                              av_get_channel_layout_nb_channels(
//                                                      avCodecContext->channels),
//                                              avFrame->nb_samples,
//                                              AV_SAMPLE_FMT_S16, 1);
        dataSize = nb * av_get_channel_layout_nb_channels(AV_CH_LAYOUT_STEREO) *
                   av_get_bytes_per_sample(AV_SAMPLE_FMT_S16);
        clock = avFrame->pts * av_q2d(time_base);
        break;
    }
    releaseAvFrame(avFrame);
    return dataSize;
}

void AudioPlayer::_play() {
//    LOGE("_play begin...");
    SLresult result;
    // 1、 创建并初始化引擎
//    SLObjectItf engineObject = NULL;
    result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
    if (SL_RESULT_SUCCESS != result) { return; }
    result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
    LOGE("engineObject: %x", engineObject);
    if (SL_RESULT_SUCCESS != result) { return; }
//    SLEngineItf engineInterface = NULL;
    result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineInterface);
    if (SL_RESULT_SUCCESS != result) { return; }

    // 2、创建并初始化混音器
//    SLObjectItf outputMixObject = NULL;
    result = (*engineInterface)->CreateOutputMix(engineInterface, &outputMixObject, 0, NULL, NULL);
    if (SL_RESULT_SUCCESS != result) { return; }
    result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
    if (SL_RESULT_SUCCESS != result) { return; }

    // 3、创建并初始化播放器
    SLDataLocator_AndroidSimpleBufferQueue android_queue = {
            SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
            2 //缓冲区数量 双缓冲区
    };
    SLDataFormat_PCM pcm = {
            SL_DATAFORMAT_PCM, //数据格式PCM
            2,  //声道数
            SL_SAMPLINGRATE_44_1,  //采样率
            SL_PCMSAMPLEFORMAT_FIXED_16, //采样位
            SL_PCMSAMPLEFORMAT_FIXED_16,  //容器大小
            SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,  //通道掩码双声道
            SL_BYTEORDER_LITTLEENDIAN  //字节序 小端
    };
    //数据源 (数据获取器+格式)
    SLDataSource slDataSource = {&android_queue, &pcm};
    // 混音器 播放声音的实体 播放器是对它的再封装
    SLDataLocator_OutputMix outputMix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
    SLDataSink audioSnk = {&outputMix, NULL};
    // 接口
    const SLInterfaceID ids[1] = {SL_IID_BUFFERQUEUE};
    const SLboolean req[1] = {SL_BOOLEAN_TRUE};
//    SLObjectItf bqPlayerObject = NULL;
    result = (*engineInterface)->CreateAudioPlayer(engineInterface, &bqPlayerObject,
                                                   &slDataSource,//数据源
                                                   &audioSnk, //混音器
                                                   1, //获取额外接口的数量，数据队列操作接口
                                                   ids, //接口ID
                                                   req //是否必须
    );
    if (SL_RESULT_SUCCESS != result) { return; }
    result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
    if (SL_RESULT_SUCCESS != result) { return; }
    // 4、开始播放
    //获取队列操作接口
//    SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue = NULL;
    result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE,
                                             &bqPlayerBufferQueue);
    if (SL_RESULT_SUCCESS != result) { return; }
    //设置回调
    result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, this);
    if (SL_RESULT_SUCCESS != result) { return; }

    //获取播放器状态接口
//    SLPlayItf bqPlayerInterface = NULL;
    result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerInterface);
    if (SL_RESULT_SUCCESS != result) { return; }
    //设置播放状态
//    LOGE("set playing...");
    result = (*bqPlayerInterface)->SetPlayState(bqPlayerInterface, SL_PLAYSTATE_PLAYING);
    if (SL_RESULT_SUCCESS != result) { return; }
    //手动调用回调方法
    bqPlayerCallback(bqPlayerBufferQueue, this);
}

void AudioPlayer::_releaseOpenSL() {

}


